/** 
Copyright (c) 2010, Sheikh Abdul Wahid Ahmed
Details @ http://extremecodeworld.codeplex.com/license
**/

using System;
using CodeGenerator.Definitions;
using System.Text;
using System.Reflection;
using EXtremecode.Logging;
using EXtremecode.Utils;
namespace CodeGenerator.Managers
{
	/// <summary>
	/// Summary description for CompileabeCodeManager.
	/// </summary>
	public class GeneratingCodeManager
	{
		//#region(|\t|\s)*Custom Code(|\t|\s)*\[Code Generator\](?<CustomCode>(.|\t|\r|\n|\s)*?)#endregion(|\t|\s)*Custom Code(|\t|\s)*\[Code Generator\]
		private static GeneratingCodeManager singleton=null;
		private AppDomain  appDomainOfCompiledAssembly=null;
        private Assembly compiledAssembly;
		private SessionCollection sessions=null;
		
		
		/// <summary>
		/// Instance
		/// </summary>
		public static GeneratingCodeManager Instance
		{
			get
			{
				if(singleton==null)
				{
					throw Logger.Write(new Exception("Singleton object not created till yet"));
				}
				return singleton;
			}
		}
		
		/// <summary>
		/// CreateInstance
		/// </summary>
		/// <param name="sessions"></param>
		/// <returns></returns>
		public static GeneratingCodeManager CreateInstance(SessionCollection sessions)
		{
			
			if(singleton==null)
			{
				singleton=new GeneratingCodeManager(sessions);
			}
			return singleton;
		}

		public static GeneratingCodeManager CreateNewInstance(SessionCollection sessions)
		{

            if (singleton != null)
            {
                singleton.UnloadCompiledAssemply();
            }
            singleton=new GeneratingCodeManager(sessions);
			return singleton;
		}
		private GeneratingCodeManager(SessionCollection sessions)
		{
			this.sessions=sessions;
		}


        public void UnloadCompiledAssemply()
        {
            if (appDomainOfCompiledAssembly != null)
            {
                AppDomain.Unload(appDomainOfCompiledAssembly);
                appDomainOfCompiledAssembly = null;
                compiledAssembly = null;
            }
        }

		
		/// <summary>
		/// CompiledAssembly
		/// </summary>
		private Assembly CompiledAssembly
		{
            get
            {
                if (compiledAssembly == null)
                {

                    appDomainOfCompiledAssembly =
                    AppDomain.CreateDomain("appDomainOfCompiledAssembly");

                    Assembly assembly = appDomainOfCompiledAssembly.Load(AssemblyName.GetAssemblyName("Utils.dll"));

                    Type type = assembly.GetType("EXtremecode.Utils.AssemblyCreator");
                    MethodInfo method = type.GetMethod("CreateAssembly"
                        , new Type[2] { typeof(StringBuilder)
                            , typeof(string[])});

                    string[] referencedAssemblies = new string[] { "System.dll"
                        , "System.Data.dll"
                        , "eXG.exe"
                        , "System.Windows.Forms.dll"
                        , "Logging.dll"
                        , "Utils.dll"
                        , "Common.dll"};

                    
                    compiledAssembly = (Assembly)method.Invoke(null
                        , new object[] { GenerateClass(sessions), referencedAssemblies });

            

                }

                return compiledAssembly;
            }
			
		}

		public StringBuilder CodeGeneratingClass
		{
			get
			{
				return GenerateClass(sessions); 
			}
		}

		/// <summary>
		/// GetSessionResult
		/// </summary>
		/// <param name="sessionName"></param>
		/// <returns></returns>
		public string GetSessionResult(string sessionName)
		{
			if(!sessions.Contains(sessionName))
			{
				throw Logger.Write(new Exception(
					string.Format("Session '{0}' not found into the assembly",sessionName)));
			}
			
			//using this line just for testing generatig code result. 
			//CodeGenerator.CodeGeneratingClass.BUZDataSetMembers();

			Type type = CompiledAssembly.GetType("CodeGenerator.CodeGeneratingClass");
			MethodInfo method=type.GetMethod(sessionName,new Type[0]);
			try
			{
			 	return method.Invoke(null,null)as string;
			}
			catch(Exception ex)
			{
				throw Logger.Write(
					string.Format("Execution faild of session method '{0}'",sessionName),
					ex);

			}
		}
		

		public StringBuilder GetSessionsResult(string[] sessionNames)
		{
			StringBuilder sb=new StringBuilder();
			foreach(string session in sessionNames)
			{
				sb.Append(GetSessionResult(session));
			}
			return sb;
		}
		/// <summary>
		/// GenerateClass
		/// </summary>
		/// <param name="sessions"></param>
		/// <returns></returns>
		private static StringBuilder GenerateClass(SessionCollection sessions)
		{
			StringBuilder sb=new StringBuilder();
			StringBuilder usingsList=new StringBuilder();
			
			try
			{
				usingsList=FileUtil.ReadFileData(Configurations.Provider.CompileableCodeUsingsFile);	
			}
			catch
			{
				//Ignore it, bcoz using list is optional.
				//we can provide our own.

				usingsList.Append(@"using System;using System.Text;" + Environment.NewLine);
			}
			
			sb.Append(usingsList.ToString() + Environment.NewLine); 
			sb.Append("namespace CodeGenerator {" + Environment.NewLine);
			sb.Append("public class CodeGeneratingClass {" + Environment.NewLine);
			
			//Append Session Metods
			foreach(string key in sessions.Keys)
			{
				sb.Append( sessions[key].Method + Environment.NewLine);
			}

			sb.Append("}}" + Environment.NewLine);

			return sb;


		}
		
		
		 
	}
}
